﻿package com.game.engine.phys
{
    import com.dusk.util.MathUtil;
    
    import nape.geom.Vec2;
    import flash.display.Graphics;

    public class Vector2D 
    {

        public var data:Object;
        private var _x:Number;
        private var _y:Number;

        public function Vector2D(posX:Number=0, posY:Number=0)
        {
            _x = posX;
            _y = posY;
            data = {};
        }

        public static function get up():Vector2D
        {
            return Vector2D.weak(0, -1);
        }

        public static function get right():Vector2D
        {
            return Vector2D.weak(1, 0);
        }

        public static function get left():Vector2D
        {
            return Vector2D.weak(-1, 0);
        }

        public static function angleBetween(vec1:Vector2D, vec2:Vector2D):Number
        {
            if (!vec1.isNormalized())
            {
                vec1 = vec1.clone().normalize();
            }
            if (!vec2.isNormalized())
            {
                vec2 = vec2.clone().normalize();
            }
            return Math.acos(vec1.dotProd(vec2));
        }

        public static function get zero():Vector2D
        {
            return new Vector2D();
        }
        
        /**
         * 线性插值
         * Result=A+t×(B−A)
         * @param vec1
         * @param vec2
         * @param t
         * @return
         */
        public static function lerp(vec1:Vector2D, vec2:Vector2D, t:Number):Vector2D
        {
            var newVec:Vector2D = vec2.subtract(vec1).multiply(t);
            newVec = newVec.add(vec1);
            return newVec;
        }
        
        /**
         * 线性插值角度
         * @param startVec
         * @param endVec
         * @param t
         * @return
         */
        public static function lerpAngle(startVec:Vector2D, endVec:Vector2D, t:Number):Vector2D
        {
            var startAngle:Number = startVec.angle;
            var endAngle:Number = endVec.angle;
            var deltaAngle:Number = endAngle - startAngle;
            var interpolatedAngle:Number = startAngle + deltaAngle * t;
            
            var resultVec:Vector2D = startVec.clone();
            resultVec.angle = interpolatedAngle;
            return resultVec;
        }
      
        
        public static function getAngleBy(vec1:Vector2D, vec2:Vector2D):Vector2D
        {
            return vec2.subtract(vec1);
        }
        
        /**
         * 创建新的Vector2D对象
         * @param posX
         * @param posY
         * @return
         */
        public static function weak(posX:Number, posY:Number):Vector2D
        {
            return new Vector2D(posX, posY);
        }


        public function get toVec2():Vec2
        {
            return Vec2.weak(x, y);
        }

        public function draw(graph:Graphics, color:uint=0):void
        {
            graph.lineStyle(0, color);
            graph.moveTo(0, 0);
            graph.lineTo(_x, _y);
        }

        public function clone():Vector2D
        {
            return new Vector2D(x, y);
        }

        public function zero():Vector2D
        {
            _x = 0;
            _y = 0;
            return this;
        }

        public function isZero():Boolean
        {
            return _x == 0 && _y == 0;
        }
        
        public function setZero():void
        {
            _x = _y = 0;
        }

        public function set length(len:Number):void
        {
            var an:Number = angle;
            _x = Math.cos(an) * len;
            _y = Math.sin(an) * len;
        }
        
        /**
         * 长度
         */
        public function get length():Number
        {
            return Math.sqrt(lengthSQ);
        }
        
        /**
         * 长度平方
         */
        public function get lengthSQ():Number
        {
            return _x * _x + _y * _y;
        }

        public function set angle(radian:Number):void
        {
            var len:Number = length;
            _x = Math.cos(radian) * len;
            _y = Math.sin(radian) * len;
        }
        
        /**
         * 根据x，y获取弧度数，可能是负值
         */
        public function get angle():Number
        {
            return Math.atan2(_y, _x);
        }
        
        /**
         * 根据x，y获取角度角度数，且一定为正值
         */
        public function get anglePositive():Number
        {
            var n:Number = Math.atan2(_y, _x);
            if (n < 0)
            {
                n += Math.PI * 2;
            }
            return MathUtil.radianToDegree(n);
        }
        
        /**
         * 归一化
         * @return
         */
        public function normalize():Vector2D
        {
            if (length == 0)
            {
                _x = 0;
                _y = 0;
                return this;
            }
            var len:Number = length;
            _x /= len;
            _y /= len;
            return this;
        }
        
        /**
         * 截取，如果目标比当前长度小则
         * @param len
         * @return
         */
        public function truncate(len:Number):Vector2D
        {
            length = Math.min(len, length);
            return this;
        }

        /**
         * 取长
         */
        public function max(len:Number):Vector2D
        {
            length = Math.max(len, length);
            return this;
        }

        public function reverse():Vector2D
        {
            _x = -_x;
            _y = -_y;
            return this;
        }

        public function isNormalized():Boolean
        {
            return length == 1;
        }
        
        /**
         * 点乘
         * @param vec
         * @return
         */
        public function dotProd(vec:Vector2D):Number
        {
            return _x * vec.x + _y * vec.y;
        }
        
        /**
         * 叉乘
         * @param vec
         * @return
         */
        public function crossProd(vec:Vector2D):Number
        {
            return _x * vec.y - _y * vec.x;
        }

        public function sign(_arg_1:Vector2D):int
        {
            return perp.dotProd(_arg_1) < 0 ? -1 : 1;
        }

        public function get perp():Vector2D
        {
            return new Vector2D(-y, x);
        }

        public function dist(_arg_1:Vector2D):Number
        {
            return Math.sqrt(distSQ(_arg_1));
        }

        public function distSQ(vec:Vector2D):Number
        {
            var _local_2:Number = vec.x - x;
            var _local_3:Number = vec.y - y;
            return _local_2 * _local_2 + _local_3 * _local_3;
        }

        public function add(vec:Vector2D):Vector2D
        {
            _x += vec.x;
            _y += vec.y;
            return new Vector2D(_x + vec.x, _y + vec.y);
        }

        public function subtract(vec:Vector2D):Vector2D
        {
            _x -= vec.x;
            _y -= vec.y;
            return new Vector2D(_x - vec.x, _y - vec.y);
        }

        public function multiply(number:Number):Vector2D
        {
            _x *= number;
            _y *= number;
            return new Vector2D(_x * number, _y * number);
        }

        public function divide(number:Number):Vector2D
        {
            _x /= number;
            _y /= number;
            return new Vector2D(_x / number, _y / number);
        }

        public function equals(_arg_1:Vector2D):Boolean
        {
            return _x == _arg_1.x && _y == _arg_1.y;
        }

        public function set x(v:Number):void
        {
            _x = v;
        }

        public function get x():Number
        {
            return _x;
        }

        public function set y(v:Number):void
        {
            _y = v;
        }

        public function get y():Number
        {
            return _y;
        }

        public function toString():String
        {
            return (("(x=" + _x) + ", y=") + _y + ")";
        }

        public function setXY(posX:Number, posY:Number):void
        {
            x = posX;
            y = posY;
        }


    }
}